#include "linux/device.h"
#include "linux/list.h"
#include "linux/errno.h"
#include "linux/string.h"
#include "linux/printk.h"

static struct list_head bus_list_head = {
    .next = &bus_list_head,
    .prev = &bus_list_head,
};

void bus_list_init(void)
{
    bus_list_head.next = &bus_list_head;
    bus_list_head.prev = &bus_list_head;
}

int bus_register(struct bus_type *bus)
{
    if (!bus)
        return -EINVAL;

    INIT_LIST_HEAD(&bus->dev_head);
    INIT_LIST_HEAD(&bus->drv_head);

    list_add_tail(&bus->list, &bus_list_head);

    return 0;
}

int bus_unregister(struct bus_type *bus)
{
    if (!bus)
        return -EINVAL;

    list_del(&bus->list);

    return 0;
}


struct bus_type *bus_find_bus_head(struct bus_type *bus)
{
    struct list_head *list;
    struct bus_type *tmp;

    list_for_each(list, &bus_list_head)
    {
        tmp = list_entry(list, struct bus_type, list);
        if (strcmp(tmp->name, bus->name) == 0)
            return tmp;
    }

    return NULL;
}

int bus_for_each_dev(struct bus_type *bus, void *data, struct device *dev, int (*fn)(struct device *dev, void *data))
{
    int ret;
    struct list_head *list;
    struct device *tmp;
    struct bus_type *this_bus_head;

    this_bus_head = bus_find_bus_head(bus);
    if (!this_bus_head)
        return 0;

    list_for_each(list, &this_bus_head->dev_head)
    {
        tmp = list_entry(list, struct device, list);
        ret = fn(tmp, data);
        if (ret < 0)
            break;
    }

    return ret;
}

int buses_init(void)
{
    bus_list_init();

    return 0;
}

